package com.apobates.forum.toro.tuple;

import com.apobates.forum.toro.tuple.strategy.ManyTripleSupplyFutureStrategy;
import com.apobates.forum.toro.tuple.strategy.ManyTripleSupplyStrategy;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 左对象是集合的Triple映射执行器
 * 左对象与右对象多对多模式的执行器
 * @param <L> 左对象类型
 * @since 20220827
 * @author xiaofanku@live.cn
 */
public class TripleManyMapperExecutor<L> {
    private final Supplier<Collection<L>> leftObjSetFun;
    private final Map<String,String> arguments;
    private static final Logger logger = LoggerFactory.getLogger(TripleManyMapperExecutor.class);

    public TripleManyMapperExecutor(Supplier<Collection<L>> leftObjSetFun, Map<String, String> arguments) {
        this.leftObjSetFun = leftObjSetFun;
        this.arguments = arguments;
    }
    /**
     *
     * @param consumer
     * @return
     * @param <M>
     * @param <R>
     */
    public <M,R> Builder<M,R, Collection<Triple<L, M, R>>> consume(Consumer<Collection<Triple<L, M, R>>> consumer){
        TripleManyResultMapperTransfer<L,M,R,Collection<Triple<L, M, R>>> transfer = new TripleManyResultMapperTransfer<>(){

            @Override
            public Consumer<Collection<Triple<L, M, R>>> getConsumer() {
                return consumer;
            }

            @Override
            public Function<Collection<Triple<L, M, R>>, Collection<Triple<L, M, R>>> getFormater() {
                return Function.identity();
            }
        };
        return new Builder<>(transfer);
    }

    /**
     *
     * @param formater
     * @return
     * @param <M>
     * @param <R>
     * @param <F>
     */
    public <M,R,F> Builder<M,R,F> format(Function<Collection<Triple<L, M, R>>, F> formater){
        TripleManyResultMapperTransfer<L,M,R,F> transfer = new TripleManyResultMapperTransfer<>(){
            @Override
            public Consumer<Collection<Triple<L, M, R>>> getConsumer() {
                return (Collection<Triple<L, M, R>> insSet)->logger.info("TripleManyMapperExecutor Default Consumer");
            }
            @Override
            public Function<Collection<Triple<L, M, R>>, F> getFormater() {
                return formater;
            }
        };
        return new Builder<>(transfer);
    }

    /**
     *
     * @param transfer
     * @return
     * @param <M>
     * @param <R>
     * @param <F>
     */
    public <M,R,F> Builder<M,R,F> transfer(TripleManyResultMapperTransfer<L,M,R,F> transfer){
        return new Builder<>(transfer);
    }

    public Supplier<Collection<L>> getLeftObjSetFun() {
        return leftObjSetFun;
    }
    public Map<String, String> getArguments() {
        return arguments;
    }

    /**
     * 使用内置的ManyTripleFutureStrategy异步策略返回映射的结果
     * @param middleFun 中对象集合查询函数
     * @param rightFun 右对象集合查询函数
     * @return 可能返回空集合
     * @param <M> 中对象类型
     * @param <R> 右对象类型
     * @param <E> 中函数的参数类型
     * @param <U> 右函数的参数类型
     */
    public <M,R,E,U> Collection<Triple<L,M,R>> get(
            Function<Collection<E>, Collection<M>> middleFun,
            Function<Collection<U>, Collection<R>> rightFun) {
        return this.get(middleFun, rightFun, new ManyTripleSupplyFutureStrategy<>());
    }

    /**
     * 使用指定聚合策略返回映射的结果
     * @param middleFun 中对象集合查询函数
     * @param rightFun 右对象集合查询函数
     * @param strategy 聚合策略
     * @return 可能返回空集合
     * @param <M> 中对象类型
     * @param <R> 右对象类型
     * @param <E> 中函数的参数类型
     * @param <U> 右函数的参数类型
     */
    public <M,R,E,U> Collection<Triple<L,M,R>> get(
            Function<Collection<E>, Collection<M>> middleFun,
            Function<Collection<U>, Collection<R>> rightFun,
            ManyTripleSupplyStrategy<L,M,R,E,U> strategy) {
        return strategy.apply(this.leftObjSetFun, middleFun, rightFun, this.arguments);
    }

    public class Builder<M,R,F>{
        private final TripleManyResultMapperTransfer<L,M,R,F> transfer;

        public Builder(TripleManyResultMapperTransfer<L, M, R, F> transfer) {
            this.transfer = transfer;
        }

        /**
         *
         * @param middleFun
         * @param rightFun
         * @return
         * @param <E>
         * @param <U>
         */
        public <E,U> F get(Function<Collection<E>, Collection<M>> middleFun, Function<Collection<U>, Collection<R>> rightFun){
            Collection<Triple<L, M, R>> triples = TripleManyMapperExecutor.this.get(middleFun, rightFun);
            return transfer.get(triples);
        }

        /**
         *
         * @param middleFun
         * @param rightFun
         * @param strategy
         * @return
         * @param <E>
         * @param <U>
         */
        public <E,U> F get(Function<Collection<E>, Collection<M>> middleFun, Function<Collection<U>, Collection<R>> rightFun, ManyTripleSupplyStrategy<L,M,R,E,U> strategy){
            Collection<Triple<L, M, R>> triples = TripleManyMapperExecutor.this.get(middleFun, rightFun, strategy);
            return transfer.get(triples);
        }
    }
}
